/*
 * The contents of this file are subject to the Mozilla Public License
 * Version 1.1 (the "License");  you may not use this file except in compliance
 * with the License.  You may obtain a copy of the License at
 * http//www.mozilla.org/MPL/
 *
 * Software distributed under the License is distributed on an "AS IS" basis,
 * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License for
 * the specific language governing rights and limitations under the License.
 *
 * The Original Code is ART Ontology API (Sesame2 Implementation).
 *
 * The Initial Developer of the Original Code is University of Roma Tor Vergata.
 * Portions created by University of Roma Tor Vergata are Copyright (C) 2007.
 * All Rights Reserved.
 *
 * ART Ontology API (Sesame2 Implementation) was developed by the Artificial Intelligence Research Group
 * (art.uniroma2.it) at the University of Roma Tor Vergata
 * Current information about the ART Ontology API (Sesame2 Implementation) can be obtained at 
 * http//art.uniroma2.it/owlart
 *
 */
package it.uniroma2.art.owlart.sesame2impl.factory;

import it.uniroma2.art.owlart.exceptions.ModelAccessException;
import it.uniroma2.art.owlart.exceptions.ModelCreationException;
import it.uniroma2.art.owlart.exceptions.ModelUpdateException;
import it.uniroma2.art.owlart.exceptions.UnsupportedRDFFormatException;
import it.uniroma2.art.owlart.exceptions.VocabularyInitializationException;
import it.uniroma2.art.owlart.io.RDFFormat;
import it.uniroma2.art.owlart.model.ARTURIResource;
import it.uniroma2.art.owlart.models.BaseRDFTripleModel;
import it.uniroma2.art.owlart.models.ModelFactory;
import it.uniroma2.art.owlart.models.OWLArtModelFactory;
import it.uniroma2.art.owlart.models.OWLModel;
import it.uniroma2.art.owlart.models.RDFModel;
import it.uniroma2.art.owlart.models.RDFSModel;
import it.uniroma2.art.owlart.resources.Resources;
import it.uniroma2.art.owlart.sesame2impl.models.BaseRDFModelSesame2Impl;
import it.uniroma2.art.owlart.sesame2impl.models.OWLModelSesame2Impl;
import it.uniroma2.art.owlart.sesame2impl.models.RDFModelSesame2Impl;
import it.uniroma2.art.owlart.sesame2impl.models.RDFSModelSesame2Impl;
import it.uniroma2.art.owlart.vocabulary.OWL;

import java.io.File;
import java.io.FileNotFoundException;
import java.io.IOException;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.openrdf.repository.RepositoryException;
import org.openrdf.repository.sail.SailRepository;
import org.openrdf.sail.SailException;
import org.openrdf.sail.inferencer.fc.DirectTypeHierarchyInferencer;
import org.openrdf.sail.inferencer.fc.ForwardChainingRDFSInferencer;
import org.openrdf.sail.memory.MemoryStore;

/**
 * This class implements {@link ModelFactory}<br/>
 * 
 * A fast and easy way to load an RDF/RDFS/OWL Model by using this Sesame2 implementation is to wrap it
 * through the OWL API convenience class {@link OWLArtModelFactory}, which handles standard configuration of
 * models of the RDF family, like loading proper vocabularies, setting baseuri/defnamespace of the loaded
 * model etc... <br/>
 * This is the code to do that:
 * 
 * <pre>
 * ModelFactory fact = OWLArtModelFactory.createModelFactory(&lt;an instance of this class&gt;);
 * </pre>
 * 
 * @author Armando Stellato <stellato@info.uniroma2.it>
 * 
 */
public class ARTModelFactorySesame2Impl implements ModelFactory {

	protected static Logger logger = LoggerFactory.getLogger(ARTModelFactorySesame2Impl.class);

	/*
	 * (non-Javadoc)
	 * 
	 * @see
	 * it.uniroma2.art.owlart.models.ModelFactory#closeModel(it.uniroma2.art.owlart.models.BaseRDFTripleModel)
	 */
	public void closeModel(BaseRDFTripleModel rep) throws ModelUpdateException {
		rep.close();
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see it.uniroma2.art.owlart.models.ModelFactory#loadRDFBaseModel(java.lang.String, java.lang.String,
	 * boolean)
	 */
	public BaseRDFModelSesame2Impl loadRDFBaseModel(String baseuri, String repositoryDirectory,
			boolean persist) throws ModelCreationException {

		File dataDir = new File(repositoryDirectory);
		if (!dataDir.exists())
			throw new ModelCreationException("you must specify an existig directory for this repository ");

		MemoryStore memStore = new MemoryStore(dataDir);
		memStore.setSyncDelay(1000L);
		memStore.setPersist(persist);

		SailRepository myRepository = new SailRepository(new DirectTypeHierarchyInferencer(
				new ForwardChainingRDFSInferencer(memStore)));

		try {
			myRepository.initialize();
		} catch (RepositoryException e) {
			throw new ModelCreationException(e.getMessage());
		}

		logger.info("Sesame2 RDF Model initialization...");
		try {
			BaseRDFModelSesame2Impl rep = new BaseRDFModelSesame2Impl(myRepository);
			return rep;
		} catch (SailException e) {
			throw new ModelCreationException(e.getMessage());
		} catch (RepositoryException e) {
			throw new ModelCreationException(e.getMessage());
		}
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see it.uniroma2.art.owlart.models.ModelFactory#loadRDFModel(java.lang.String, java.lang.String,
	 * boolean)
	 */
	public RDFModel loadRDFModel(String baseuri, String repositoryDirectory, boolean persist)
			throws ModelCreationException {
		BaseRDFModelSesame2Impl baserep = loadRDFBaseModel(baseuri, repositoryDirectory, persist);
		try {
			RDFModelSesame2Impl rep = new RDFModelSesame2Impl(baserep);
			return rep;
		} catch (VocabularyInitializationException e) {
			throw new ModelCreationException(e);
		}
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see it.uniroma2.art.owlart.models.ModelFactory#loadRDFSModel(java.lang.String, java.lang.String,
	 * boolean)
	 */
	public RDFSModel loadRDFSModel(String baseuri, String repositoryDirectory, boolean persist)
			throws ModelCreationException {
		BaseRDFModelSesame2Impl baserep = loadRDFBaseModel(baseuri, repositoryDirectory, persist);
		try {
			RDFSModelSesame2Impl rep = new RDFSModelSesame2Impl(baserep);
			return rep;
		} catch (VocabularyInitializationException e) {
			throw new ModelCreationException(e);
		}
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see it.uniroma2.art.owlart.models.ModelFactory#loadOWLModel(java.lang.String, java.lang.String,
	 * boolean)
	 */
	public OWLModel loadOWLModel(String baseuri, String repositoryDirectory, boolean persist)
			throws ModelCreationException {
		BaseRDFModelSesame2Impl baserep = loadRDFBaseModel(baseuri, repositoryDirectory, persist);
		try {
			OWLModelSesame2Impl rep = new OWLModelSesame2Impl(baserep);
			ARTURIResource owl = rep.createURIResource(OWL.NAMESPACE);
			logger.debug("owl namespace: " + owl.getURI());
			rep.addRDF(Resources.class.getResource("owl.rdfs"), OWL.NAMESPACE, RDFFormat.RDFXML, owl);
			return rep;
		} catch (VocabularyInitializationException e) {
			throw new ModelCreationException(e);
		} catch (FileNotFoundException e) {
			throw new ModelCreationException(e);
		} catch (IOException e) {
			throw new ModelCreationException(e);
		} catch (ModelAccessException e) {
			throw new ModelCreationException(e);
		} catch (ModelUpdateException e) {
			throw new ModelCreationException(e);
		} catch (UnsupportedRDFFormatException e) {
			throw new ModelCreationException(e);
		}
	}

}
